package com.learn.interceptor;

import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.http.HttpStatus;
import com.learn.base.ApiResult;
import com.learn.base.ApiResultUtils;
import com.learn.base.R;
import com.learn.constant.GlobalParamsConstants;
import com.learn.constant.HeadersConstants;
import com.learn.constant.LogTraceConstants;
import com.learn.dto.base.BaselineReqInfo;
import com.learn.dto.base.TokenData;
import com.learn.emuns.LearnResultEnums;
import com.learn.service.AdminTokenService;
import com.learn.utils.JsonUtil;
import com.learn.utils.JwtUtil;
import com.learn.utils.ThreadLocalUtil;
import com.learn.utils.TokenUtils;
import org.slf4j.MDC;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;

public class JwtInterceptor implements HandlerInterceptor
{
	ApiResult<Serializable> authResp = ApiResultUtils.build (LearnResultEnums.AUTH_FAIL.getStatus (),
			LearnResultEnums.AUTH_FAIL.getErrMsg (), null);

	@Override
	public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
	{

		BaselineReqInfo baselineReqInfo = new BaselineReqInfo ();
		handleBaselineReqInfo (request, HeadersConstants.AUTHORIZATION, baselineReqInfo);
		handleBaselineReqInfo (request, HeadersConstants.TRACE_ID, baselineReqInfo);
		handleBaselineReqInfo (request, HeadersConstants.CHANNEL, baselineReqInfo);
		handleBaselineReqInfo (request, HeadersConstants.USER_AGENT, baselineReqInfo);
		handleBaselineReqInfo (request, HeadersConstants.CSRF_TOKEN, baselineReqInfo);
		handleBaselineReqInfo (request, HeadersConstants.NET_TYPE, baselineReqInfo);
		handleBaselineReqInfo (request, HeadersConstants.DEVICE_INFO, baselineReqInfo);
		handleBaselineReqInfo (request, HeadersConstants.CHANNEL_SOURCE, baselineReqInfo);
		handleBaselineReqInfo (request, HeadersConstants.MM_SOURCE, baselineReqInfo);
		handleBaselineReqInfo (request, HeadersConstants.FORWARDED_FOR, baselineReqInfo);
		handleBaselineReqInfo (request, HeadersConstants.SOURCE, baselineReqInfo);
		handleBaselineReqInfo (request, HeadersConstants.X_CHANNEL_SRC, baselineReqInfo);
		handleBaselineReqInfo (request, HeadersConstants.X_ACTION_ID, baselineReqInfo);

		// 把traceId保存在MDC中
		MDC.put (LogTraceConstants.MDC_TRACE_ID_KEY, baselineReqInfo.get (HeadersConstants.TRACE_ID));

		response.setContentType ("application/json;charset=UTF-8");
		String token = request.getHeader (HeadersConstants.AUTHORIZATION);
		if (token == null || token.isEmpty ())
		{
			response.setStatus (HttpStatus.HTTP_FORBIDDEN);
			response.getWriter ().write (JsonUtil.to (authResp));
			return false;
		}

		try
		{

			// JWT解析验证
			String requestURI = request.getRequestURI ();
			String method = request.getMethod ();
			TokenData adminTokenFromHeader = TokenUtils.getAdminTokenFromHeader (token);
			AdminTokenService adminTokenService = SpringUtil.getBean (AdminTokenService.class);
			R<Boolean> validateResp = adminTokenService.validateAdminJwt (adminTokenFromHeader.getApplyType (),
					adminTokenFromHeader.getToken (), requestURI, method);

			if (Boolean.FALSE.equals (validateResp.getData ()))
			{
				response.setStatus (HttpStatus.HTTP_FORBIDDEN);
				response.getWriter ().write (JsonUtil.to (authResp));
				return false;
			}
			
			//JWT验证解析成功，保存请求上下文的token
			JwtUtil.TokenInfo tokenInfo = JwtUtil.parseTokenInfo (adminTokenFromHeader.getToken ());

			baselineReqInfo.put (GlobalParamsConstants.CURRENT_ACCOUNT, tokenInfo.getAccount ());
			baselineReqInfo.put (GlobalParamsConstants.CURRENT_USER_ID, tokenInfo.getSubId ());
			baselineReqInfo.put (GlobalParamsConstants.CURRENT_TENANT_ID, tokenInfo.getTenantId ());
			baselineReqInfo.put (GlobalParamsConstants.JWT, adminTokenFromHeader.getToken ());
			baselineReqInfo.put (GlobalParamsConstants.CURRENT_CHANNEL, tokenInfo.getChannel ());
			baselineReqInfo.put (GlobalParamsConstants.CURRENT_LOGIN_METHOD, tokenInfo.getLoginMethod ());
			baselineReqInfo.put (GlobalParamsConstants.CURRENT_CLIENT_TYPE, tokenInfo.getClientType ());

			//PUT MDC
			MDC.put (LogTraceConstants.MDC_USER_NAME_KEY, tokenInfo.getAccount ());
			// BaselineReqInfo保存在线程上下文
			ThreadLocalUtil.getInstance ().bind (baselineReqInfo);
			return true;
		}
		catch (Exception e)
		{
			response.setStatus (HttpStatus.HTTP_FORBIDDEN);
			response.getWriter ().write (JsonUtil.to (authResp));
			return false;
		}
	}


	/**
	 * 对BaselineReqInfo对象进行处理
	 * 将请求头中的对应信息保存到BaselineReqInfo对象中
	 *
	 * @param httpServletRequest http请求对象实例
	 * @param headerName         请求头名称
	 * @param baselineReqInfo    BaselineReqInfo对象实例
	 */
	private void handleBaselineReqInfo (HttpServletRequest httpServletRequest, String headerName,
			BaselineReqInfo baselineReqInfo)
	{
		String headerValue = httpServletRequest.getHeader (headerName);
		if (headerValue != null)
		{
			baselineReqInfo.put (headerName, headerValue);
		}
	}
}